package unix

import (
	"net"
	"strings"

	"gddgame.cc/galaxy/satellite"

	"gddgame.cc/galaxy/utils/def"
)

type unix struct {
	def.Logger

	addr      *net.UnixAddr
	listener  net.Listener
	connected bool
	accept    chan satellite.Conn
}

func NewTransport(unixAddr *net.UnixAddr) *unix {
	t := &unix{
		addr: unixAddr,
	}
	return t
}

func (transport *unix) Dial() (satellite.Conn, error) {
	conn, err := net.DialUnix("unix", nil, transport.addr)
	if err != nil {
		return nil, err
	}

	return satellite.NewBaseConn(conn, transport), err
}
func (transport *unix) Listen() (<-chan satellite.Conn, error) {
	listener, err := net.ListenUnix("unix", transport.addr)
	if err != nil {
		return nil, err
	}

	transport.listener = listener

	transport.connected = true
	if transport.Logger != nil {
		transport.Debugf("Listen unix: %#v", transport.addr)
	}
	transport.accept = make(chan satellite.Conn)
	go func() {
		for {
			if !transport.connected {
				goto Close
			}
			conn, err := transport.listener.Accept()
			if err != nil {
				if strings.Contains(err.Error(), "closed") {
					goto Close
				}
				if transport.Logger != nil {
					transport.Errorf("Socket err:%s", err)
				}
			} else {
				if transport.Logger != nil {
					transport.Debugf("unix new conn:#v", conn)
				}
				transport.accept <- satellite.NewBaseConn(conn, transport)
			}
		}
	Close:
		close(transport.accept)
		_ = transport.Close()
	}()
	return transport.accept, nil
}

func (transport *unix) Type() satellite.TransportType {
	return "unix"
}
func (transport *unix) Schema() string {
	return transport.addr.String()
}
func (transport *unix) SetLogger(logger def.Logger) {
	transport.Logger = logger
}

func (transport *unix) Close() error {
	if !transport.connected {
		return nil
	}
	transport.connected = false
	err := transport.listener.Close()
	if err != nil {
		return err
	}
	return nil
}

func (transport *unix) Connected() bool {
	return transport.connected
}
